{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# **Differentiation Infrastructure in Deepchem**\n",
    "\n",
    "Author : Rakshit Kr. Singh : [Website](https://sudo-rsingh.github.io/) : [LinkedIn](https://www.linkedin.com/in/rakshit-singh-ai/) : [GitHub](https://github.com/sudo-rsingh)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Scientific advancement in machine learning hinges on the effective resolution of complex optimization problems. From material property design to drug discovery, these problems often involve numerous variables and intricate relationships. Traditional optimization techniques often face hurdles when addressing such challenges, often resulting in slow convergence or solutions deemed unreliable. We introduce solutions that are differentiable and also seamlessly integrable into machine learning systems, offering a novel approach to resolving these complexities.\n",
    "\n",
    "This tutorials introduces DeepChem's comprehensive set of differentiable optimisation tools to empower researchers across the physical sciences. DeepChem addresses limitations of conventional methods by offering a diverse set of optimization algorithms. These includes established techniques like Broyden's first and second methods alongside cutting-edge advancements, allowing researchers to select the most effective approach for their specific problem.\n",
    "\n",
    "## Colab\n",
    "\n",
    "This tutorial and the rest in this sequence are designed to be done in Google colab. If you'd like to open this notebook in colab, you can use the following link.\n",
    "\n",
    "[![Open In Colab](https://colab.research.google.com/assets/colab-badge.svg)](https://colab.research.google.com/github/deepchem/deepchem/blob/master/examples/tutorials/Differentiation_Infrastructure_in_Deepchem.ipynb)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Overview of Differentiation Utilities in Deepchem\n",
    "\n",
    "DeepChem provides a number of optimisation algorithms and Utilities for implementing more algorithms. Some of the optimisation algorithms provided by DeepChem are:\n",
    "- Broyden's First Method\n",
    "- Broyden's Second Method\n",
    "- Anderson Acceleration\n",
    "- Gradient Descent\n",
    "- Adam\n",
    "\n",
    "Along with these optimisation algorithms, DeepChem also provides a number of utilities for implementing more algorithms."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## What are Non Linear Equations? and why do they matter?\n",
    "\n",
    "Nonlinear equations are mathematical expressions where the relationship between the variables is not linear. Unlike linear equations, which have a constant rate of change, nonlinear equations involve terms with higher powers or functions like exponentials, logarithms, trigonometric functions, etc.\n",
    "\n",
    "Nonlinear equations are essential across various disciplines, including physics, engineering, economics, biology, and finance. They describe complex relationships and phenomena that cannot be adequately modeled with linear equations. From gravitational interactions in celestial bodies to biochemical reactions in living organisms, non-linear equations play a vital role in understanding and predicting real-world systems. Whether it's optimizing structures, analyzing market dynamics, or designing machine learning algorithms.\n",
    "\n",
    "### Some Simple Non Linear Equations:\n",
    "\n",
    "$f(x) = sin(x)$, is a trigonometric function defined for all real numbers.\n",
    "It represents the ratio of the length of the side opposite an angle in a right triangle to the length of the hypotenuse.\n",
    "\n",
    "$f(x) = cos(x)$, is an another trigonometric function.\n",
    "It represents the ratio of the length of the adjacent side of a right triangle to the length of the hypotenuse when x is the measure of an acute angle.\n",
    "\n",
    "$f(x) = x^2$, is a parabola, symmetric around the y-axis, with its vertex at the origin.\n",
    "It represents a mathematical model of quadratic growth or decay. In physical systems, it often describes phenomena where the rate of change is proportional to the square of the quantity involved."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 900x300 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import numpy as np\n",
    "\n",
    "x = np.linspace(0, 10, 100)\n",
    "y1 = np.sin(x)\n",
    "y2 = np.cos(x)\n",
    "y3 = x**2\n",
    "\n",
    "fig, axs = plt.subplots(1, 3, figsize=(9, 3))  \n",
    "\n",
    "axs[0].plot(x, y1, color='blue')\n",
    "axs[0].set_title('Sin')\n",
    "\n",
    "axs[1].plot(x, y2, color='red')\n",
    "axs[1].set_title('Cos')\n",
    "\n",
    "axs[2].plot(x, y3, color='green')\n",
    "axs[2].set_title('x^2')\n",
    "\n",
    "plt.tight_layout()\n",
    "\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Root Finder Methods\n",
    "\n",
    "`deepchem.utils.differentiation_utils.optimize.rootfinder` provides a collection of algorithms for solving nonlinear equations. These methods are designed to find the roots of functions efficiently, making them indispensable for a wide range of applications in mathematics, physics, engineering, and other fields.\n",
    "\n",
    "At its core, rootfinding seeks to determine the solutions (roots) of equations, where a function equals zero. This operation plays a pivotal role in numerous real-world applications, making it indispensable in both theoretical and practical domains."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Broyden's First Method:\n",
    "\n",
    "Broyden's First Method is an iterative numerical method used for solving systems of nonlinear equations. It's particularly useful when the Jacobian matrix (the matrix of partial derivatives of the equations) is difficult or expensive to compute. \n",
    "\n",
    "Broyden's Method is an extension of the Secant Method for systems of nonlinear equations. It iteratively updates an approximation to the Jacobian matrix using the information from previous iterations. The algorithm converges to the solution by updating the variables in the direction that minimizes the norm of the system of equations.\n",
    "\n",
    "Steps:\n",
    "1. Initialize the approximation to the Jacobian matrix.\n",
    "$$J_{k}$$\n",
    "\n",
    "2. Initialize the variables.\n",
    "$$X_{k} = f(X_{k})$$\n",
    "\n",
    "3. Compute the function values.\n",
    "$$f_{k} = f(X_{k})$$\n",
    "\n",
    "4. Update the variables.\n",
    "$$X_{k+1} = X_{k+1} - J_{k}^{-1}f_k$$\n",
    "\n",
    "5. Compute the change in variables.\n",
    "$$\\Delta X_{k+1} = X_{k+1} - X_{k}$$\n",
    "\n",
    "6. Compute the function values.\n",
    "$$f_{k+1} = f(X_{k+1})$$\n",
    "\n",
    "7. Update the approximation to the Jacobian matrix.\n",
    "$$J^{-1}_{k+1} = J^{-1}_{k} + \\frac{(\\Delta X_{k+1} - J^{-1}_{k} \\Delta f_{k+1}) \\Delta X^{T}_{k+1} J^{-1}_{k}}{\\Delta X^{T}_{k+1} J^{-1}_{k} \\Delta f_{k+1}}$$\n",
    "\n",
    "8. Repeat steps 4-7 until convergence criteria are met.\n",
    "\n",
    "#### References:\n",
    "\n",
    "[1] \"A class of methods for solving nonlinear simultaneous equations\" by Charles G. Broyden"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Root By Broyden's First Method:\n",
      "tensor([[-0.0459],\n",
      "        [-0.0663]], grad_fn=<_RootFinderBackward>)\n",
      "Function Value at Calculated Root:\n",
      "tensor([[1.1735e-07],\n",
      "        [1.7881e-07]], grad_fn=<AddBackward0>)\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from deepchem.utils.differentiation_utils import rootfinder\n",
    "def func1(y, A):\n",
    "    return torch.tanh(A @ y + 0.1) + y / 2.0\n",
    "A = torch.tensor([[1.1, 0.4], [0.3, 0.8]]).requires_grad_()\n",
    "y0 = torch.zeros((2,1))\n",
    "\n",
    "# Broyden's First Method\n",
    "yroot = rootfinder(func1, y0, params=(A,), method='broyden1')\n",
    "print(\"Root By Broyden's First Method:\")\n",
    "print(yroot)\n",
    "print(\"Function Value at Calculated Root:\")\n",
    "print(func1(yroot, A))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(tensor(2.2752, grad_fn=<ViewBackward0>),\n",
       " tensor(1.7881e-06, grad_fn=<AddBackward0>))"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "from deepchem.utils.differentiation_utils.optimize.rootsolver import broyden1\n",
    "def fcn(x):\n",
    "   return x**2 - 4 + torch.tan(x)\n",
    "x0 = torch.tensor(0.0, requires_grad=True)\n",
    "x = broyden1(fcn, x0)\n",
    "x, fcn(x)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Broyden's Second Method:\n",
    "\n",
    "Broyden's Second Method differs from the first method in how it updates the approximation to the Jacobian matrix. Instead of using the change in variables and function values, it uses the change in the residuals (the difference between the function values and the target values) to update the Jacobian matrix. This approach can be more stable and robust in certain situations.\n",
    "\n",
    "Steps:\n",
    "\n",
    "1...6 are same as Broyden's First Method.\n",
    "\n",
    "7. Update the approximation to the Jacobian matrix.\n",
    "$$J^{-1}_{k+1} = J^{-1}_{k} + \\frac{(\\Delta X_{k+1} - J^{-1}_{k} \\Delta f_{k+1}) \\Delta f^{T}_{k+1}}{\\Delta f^{T}_{k+1} \\Delta f_{k+1}}$$\n",
    "\n",
    "8. Repeat steps 4-7 until convergence criteria are met.\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Root by Broyden's Second Method:\n",
      "tensor([[-0.0459],\n",
      "        [-0.0663]], grad_fn=<_RootFinderBackward>)\n",
      "Function Value at Calculated Root:\n",
      "tensor([[ 1.0300e-06],\n",
      "        [-3.2783e-07]], grad_fn=<AddBackward0>)\n"
     ]
    }
   ],
   "source": [
    "# Broyden's Second Method\n",
    "import torch\n",
    "from deepchem.utils.differentiation_utils import rootfinder\n",
    "def func1(y, A):\n",
    "    return torch.tanh(A @ y + 0.1) + y / 2.0\n",
    "A = torch.tensor([[1.1, 0.4], [0.3, 0.8]]).requires_grad_()\n",
    "y0 = torch.zeros((2,1))\n",
    "\n",
    "yroot = rootfinder(func1, y0, params=(A,), method='broyden2')\n",
    "print(\"\\nRoot by Broyden's Second Method:\")\n",
    "print(yroot)\n",
    "print(\"Function Value at Calculated Root:\")\n",
    "print(func1(yroot, A))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Equilibrium Methods (Fixed Point Iteration)\n",
    "\n",
    "`deepchem.utils.differentiation_utils.optimize.equilibrium` contains algorithms for solving equilibrium problems, where the goal is to find a fixed point of a function. While all the rootfinding methods can be used to solve equilibrium problems, these specialized algorithms are designed to exploit the structure of equilibrium problems for more efficient convergence.\n",
    "\n",
    "Equilibrium methods are essential in machine learning for optimizing models, ensuring stability and convergence, regularizing parameters, and analyzing strategic interactions in multi-agent systems. By leveraging equilibrium principles and techniques, machine learning practitioners can train more robust and generalizable models capable of addressing a wide range of real-world challenges.\n",
    "\n",
    "### The Fixed-Point Problem:\n",
    "Given the function $f: \\mathbb{R}^{n} \\rightarrow \\mathbb{R}^{n}$, compute a fixed-point $x^{*} \\in \\mathbb{R}^{n}$ such that\n",
    "$$x^{*} = f(x^{*})$$\n",
    "\n",
    "### Classical Approach:\n",
    "Steps:\n",
    "1. Initialize the variables. $x_{k}$\n",
    "2. Compute the function values. $f_{k} = f(x_{k})$\n",
    "3. Update the variables. $x_{k+1} = f_{k}$\n",
    "4. Repeat steps 2-3 until convergence criteria are met."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Anderson Acceleration Approach (Anderson Mixing):\n",
    "Anderson Acceleration is an iterative method for accelerating the convergence of fixed-point \n",
    "iterations. It combines information from previous iterations to construct a better approximation to \n",
    "the fixed-point. The algorithm uses a history of function values and updates to compute a new \n",
    "iterate that minimizes the residual norm.\n",
    "\n",
    "Steps:\n",
    "1. $\\textbf{Initialize point: } x_{0}$, fixed-point mapping $f : \\mathbb{R}^{n} \\rightarrow \\mathbb{R}^{n}$\n",
    "\n",
    "2. $\\textbf{for}$ $k = 0, 1,... $ $\\textbf{do}$\n",
    "   - Choose $m_{k}$ (e.g., $m_{k} = min(m, k)$  for some integer $m \\geq 0$).\n",
    "   - Select weights $\\alpha_{k}^{j}$ based on the last $m_{k}$ iterations satisfying $\\sum_{j=0}^{m_{k}} \\alpha_{j}^{k} = 1$.\n",
    "   - $x_{k+1} = \\sum_{j=0}^{m_{k}} \\alpha_{j}^{k}f(x_{k-m_{k}+j})$.\n",
    "3. $\\textbf{end}$ $\\textbf{for}$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Root by Anderson Acceleration: 1.4142135381698608\n",
      "Function Value at Calculated Root: 1.4142135381698608\n"
     ]
    },
    {
     "data": {
      "image/png": "iVBORw0KGgoAAAANSUhEUgAAAjcAAAHHCAYAAABDUnkqAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjguMiwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy8g+/7EAAAACXBIWXMAAA9hAAAPYQGoP6dpAABlJElEQVR4nO3dd3hTZf8G8Ps0bZLO0EKnFFpmmaUMFVBWEayI8KIyZJTl+L0gS0QQmYqAsreoUEC0gEwRZE9BpuUF2VCG0MHqpit5fn+0CYQOmjbJ6bg/15WL5JyTc745Ccnd53nOOZIQQoCIiIiolLCRuwAiIiIic2K4ISIiolKF4YaIiIhKFYYbIiIiKlUYboiIiKhUYbghIiKiUoXhhoiIiEoVhhsiIiIqVRhuiIiIqFRhuCEis/jjjz/QoEEDqNVqSJKEuLg4uUsCAPTt2xd+fn5yl1FmFdf9v3//fkiShP3798tdClkAww1ZzLVr1/Dhhx+iSpUqUKvVcHFxQfPmzTF37lw8fvxY7vLIjB48eICuXbvC3t4eCxcuxKpVq+Do6Pjc5y1atAiSJOGll16yQpWl37Zt2yBJEnx8fKDT6eQup1hYtGgRwsLC5C6DrMxW7gKodPr999/x7rvvQqVSoU+fPqhbty7S09Nx+PBhfPrpp/jnn3+wdOlSucskMzlx4gQSExPx5Zdfom3btgV+3urVq+Hn54fjx4/j6tWrqFatmgWrLP30+/PGjRvYu3evSe9FabVo0SJUqFABffv2NZreokULPH78GEqlUp7CyKLYckNmFxkZie7du6Ny5co4f/485s6di/fffx+DBg3CL7/8gvPnz6NOnTpyl1kkqamp/Mv4KbGxsQCAcuXKFfg5kZGROHLkCGbNmgV3d3esXr3aQtWZjxCi2LY6JicnY/PmzRgxYgSCgoJKxP40lTn3v42NDdRqNWxs+DNYGvFdJbP75ptvkJSUhB9//BHe3t455lerVg1Dhw41PM7MzMSXX36JqlWrQqVSwc/PD59//jnS0tKMnufn54c333wThw8fxosvvgi1Wo0qVapg5cqVhmVOnjwJSZKwYsWKHNvdsWMHJEnC1q1bDdPu3LmD/v37w9PTEyqVCnXq1MGyZcuMnqfvmw8PD8cXX3yBF154AQ4ODkhISAAArFu3DrVr14ZarUbdunWxcePGXMcZ6HQ6zJkzB3Xq1IFarYanpyc+/PBDPHr0yOTXqRcXF4fhw4fDz88PKpUKFStWRJ8+fXD//n3DMmlpaZgwYQKqVasGlUoFX19fjBo1Ksf+zcu6devQqFEj2Nvbo0KFCujVqxfu3LljmN+qVSuEhoYCAJo0aQJJknL8lZyb1atXw9XVFR06dMA777yT64/xjRs3IEkSZsyYgaVLlxo+I02aNMGJEydyLL9p0ybUrVvX6L3IjanvxY4dO9C4cWPY29vju+++AwDs2rULr7zyCsqVKwcnJyfUrFkTn3/+udHzY2NjMWDAAHh6ekKtViMwMDDHZ9PU15iXjRs34vHjx3j33XfRvXt3bNiwAampqTmWS01NxcSJE1GjRg2o1Wp4e3ujS5cuuHbtmtH+mTt3LurVqwe1Wg13d3e8/vrrOHnypNG6fvrpJ8Nnw83NDd27d8ft27efW6s59v/y5cvRpk0beHh4QKVSoXbt2li8eHGO5//zzz84cOAAJEmCJElo1aoVgLzH3Dzv8w5kjSNycnLCnTt30LlzZzg5OcHd3R0jR46EVqt97usnKxBEZvbCCy+IKlWqFHj50NBQAUC88847YuHChaJPnz4CgOjcubPRcpUrVxY1a9YUnp6e4vPPPxcLFiwQDRs2FJIkiXPnzhmWq1KlinjjjTdybKdfv37C1dVVpKenCyGEiI6OFhUrVhS+vr5i8uTJYvHixeKtt94SAMTs2bMNz9u3b58AIGrXri0aNGggZs2aJaZOnSqSk5PF1q1bhSRJon79+mLWrFli3LhxwtXVVdStW1dUrlzZaPsDBw4Utra24v333xdLliwRn332mXB0dBRNmjQx1GTK60xMTBR169YVCoVCvP/++2Lx4sXiyy+/FE2aNBF///23EEIIrVYr2rVrJxwcHMSwYcPEd999JwYPHixsbW1Fp06dnvveLF++XAAQTZo0EbNnzxajR48W9vb2ws/PTzx69EgIIcTOnTvFBx98IACIyZMni1WrVokjR448d90BAQFiwIABQgghDh48KACI48ePGy0TGRkpAIigoCBRrVo1MX36dPHNN9+IChUqiIoVKxrttx07dggbGxtRt25dMWvWLDF27Fih0WhEnTp1ivReVKtWTbi6uorRo0eLJUuWiH379olz584JpVIpGjduLObOnSuWLFkiRo4cKVq0aGF4bkpKiqhVq5aws7MT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",
      "text/plain": [
       "<Figure size 640x480 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import torch\n",
    "import matplotlib.pyplot as plt\n",
    "from deepchem.utils.differentiation_utils.optimize.equilibrium import anderson_acc\n",
    "x_value, f_value = [], []\n",
    "def fcn(x, a):\n",
    "    x_value.append(x.item())\n",
    "    f_value.append((a/x + x).item()/2)\n",
    "    return (a/x + x)/2\n",
    "a = 2.0\n",
    "x0 = torch.tensor([1.0], requires_grad=True)\n",
    "x = anderson_acc(fcn, x0, params=[a], maxiter=16)\n",
    "print(\"Root by Anderson Acceleration:\", x.item())\n",
    "print(\"Function Value at Calculated Root:\", fcn(x, a).item())\n",
    "\n",
    "# Plotting the convergence of Anderson Acceleration\n",
    "plt.plot(x_value, label='Input Value')\n",
    "plt.plot(f_value, label='Func. Value by Anderson Acce.')\n",
    "plt.legend(loc='lower right')\n",
    "plt.xlabel('Iteration')\n",
    "plt.ylabel('Function Value')\n",
    "plt.title('Convergence of Anderson Acceleration')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Minimizer\n",
    "\n",
    "`deepchem.utils.differentiation_utils.optimize.minimizer` provides a collection of algorithms for minimizing functions. These methods are designed to find the minimum of a function efficiently, making them indispensable for a wide range of applications in mathematics, physics, engineering, and other fields.\n",
    "\n",
    "Minimization algorithms, including variants of gradient descent like ADAM, are fundamental tools in various fields of science, engineering, and optimization."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Gradient Descent\n",
    "\n",
    "Gradient descent is a method for unconstrained mathematical optimization. It is a first-order iterative algorithm for finding a local minimum of a differentiable multivariate function.\n",
    "\n",
    "It is used to minimize the cost function in various machine learning and optimization problems. It iteratively updates the parameters in the direction of the negative gradient of the cost function.\n",
    "\n",
    "Steps:\n",
    "\n",
    "1. $\\textbf{Initialize Parameters: }$ Denote the parameter vector to be optimized - $\\theta$ and $\\theta_0$ represent the initial guess.\n",
    "    \n",
    "2. $\\textbf{Compute Gradient: }$ Calculate the gradient of the cost function $J(\\theta)$ with respect to each parameter.\n",
    "\n",
    "   $$\\nabla J(\\theta) = \\left[ \\frac{\\partial J(\\theta)}{\\partial \\theta_1}, \\frac{\\partial J(\\theta)}{\\partial \\theta_2}, \\ldots, \\frac{\\partial J(\\theta)}{\\partial \\theta_n} \\right]^T$$\n",
    "\n",
    "   - $\\textbf{Update Parameters: }$ Adjust the parameters in the opposite direction of the gradient to minimize the cost function according to the learning rate $\\alpha$:\n",
    "\n",
    "   $$\\theta = \\theta - \\alpha \\nabla J(\\theta)$$\n",
    "    \n",
    "   - $\\textbf{Repeat: }$ Steps 2 and 3 until the algorithm converges or Stops."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Minimum by Gradient Descent: 0.9973406791687012\n",
      "Function Value at Calculated Minimum: (tensor(3.0000), tensor(-0.0053))\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from deepchem.utils.differentiation_utils.optimize.minimizer import gd\n",
    "def fcn(x):\n",
    "    return 2 * x + (x - 2) ** 2, 2 * (x - 2) + 2\n",
    "x0 = torch.tensor(0.0, requires_grad=True)\n",
    "x = gd(fcn, x0, [])\n",
    "print(\"Minimum by Gradient Descent:\", x.item())\n",
    "print(\"Function Value at Calculated Minimum:\", fcn(x)[0].item())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### ADAM (Adaptive Moment Estimation)\n",
    "\n",
    "ADAM is an optimization algorithm used for training deep learning models. It's an extension of the gradient descent optimization algorithm and combines the ideas of both momentum and RMSProp algorithms.\n",
    "\n",
    "Steps:\n",
    "1. $\\textbf{Initialization: }$ ADAM initializes two moving average variables: $m$ (the first moment, similar to momentum) and $v$ (the second moment, similar to RMSProp).\n",
    "    \n",
    "2. $\\textbf{Compute Gradients: }$ At each iteration of training, the gradients of the parameters concerning the loss function are computed.\n",
    "\n",
    "3. $\\textbf{Update Moving Averages: }$ The moving averages $m$ and $v$ are updated using exponential decay, with momentum and RMSProp components respectively:\n",
    "\n",
    "$$m_{t} = \\beta_{1} m_{t-1} + (1 - \\beta_{1}) \\nabla J(\\theta_{t})$$\n",
    "$$v_{t} = \\beta_{2} v_{t-1} + (1 - \\beta_{2}) (\\nabla J(\\theta_{t}))^2$$\n",
    "\n",
    "4. $\\textbf{Bias Correction: }$ Due to the initialization of the moving averages to zero vectors, there's a bias towards zero, especially during the initial iterations. To correct this bias, ADAM applies a bias correction step:\n",
    "\n",
    "$$\\hat{m}_{t} = \\frac{m_{t}}{1 - \\beta_{1}^t}$$\n",
    "$$\\hat{v}_{t} = \\frac{v_{t}}{1 - \\beta_{2}^t}$$\n",
    "\n",
    "5. $\\textbf{Update Parameters: }$ Finally, the parameters (weights and biases) of the model are updated using the moving averages and the learning rate $\\alpha$:\n",
    "\n",
    "$$\\theta_{t+1} = \\theta_{t} - \\alpha \\frac{\\hat{m}_{t}}{\\sqrt{\\hat{v}_{t}} + \\epsilon}$$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "X at Minimum by Adam: 1.0067708492279053\n",
      "Function Value at Calculated Minimum: 3.0000457763671875\n"
     ]
    }
   ],
   "source": [
    "import torch\n",
    "from deepchem.utils.differentiation_utils.optimize.minimizer import adam\n",
    "def fcn(x):\n",
    "    return 2 * x + (x - 2) ** 2, 2 * (x - 2) + 2\n",
    "x0 = torch.tensor(10.0, requires_grad=True)\n",
    "x = adam(fcn, x0, [], maxiter=20000)\n",
    "print(\"X at Minimum by Adam:\", x.item())\n",
    "print(\"Function Value at Calculated Minimum:\", fcn(x)[0].item())"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Conclusion\n",
    "\n",
    "Differentiable optimization techniques are essential for many advanced computational experiments involving Environment Simulations like DFT, Physics Informed Neural Networks and as fundamental mathematical foundation for Molecular Simulation like Monte Carlo and Molecular Dynamics.\n",
    "\n",
    "By integrating deep learning into simulations, we optimize efficiency and accuracy by leveraging trainable neural networks to replace costly or less precise components. This advancement holds immense potential for expediting scientific advancements and addressing longstanding mysteries with greater efficacy."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## References\n",
    "\n",
    "[1] Raissi M, Perdikaris P, Karniadakis GE. Physics-informed neural networks: A deep learning framework for solving forward and inverse problems involving nonlinear partial differential equations. Journal of Computational physics (2019)\n",
    "\n",
    "[2] Muhammad F. Kasim, Sam M. Vinko. Learning the exchange-correlation functional from nature with fully differentiable density functional theory. 2021 American Physical Society\n",
    "\n",
    "[3] Nathan Argaman, Guy Makov. Density Functional Theory -- an introduction. American Journal of Physics 68 (2000), 69-79\n",
    "\n",
    "[4] John Ingraham et al. Learning Protein Structure with a Differentiable Simulator. ICLR.\n",
    "2019."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Citing This Tutorial\n",
    "\n",
    "If you found this tutorial useful please consider citing it using the provided BibTeX.\n",
    "\n",
    "```bibtex\n",
    "@manual{Quantum Chemistry, \n",
    " title={Differentiation Infrastructure in Deepchem}, \n",
    " organization={DeepChem},\n",
    " author={Singh, Rakshit kr.},\n",
    " howpublished = {\\url{https://github.com/deepchem/deepchem/blob/master/examples/tutorials/Differentiation_Infrastructure_in_Deepchem.ipynb}}, \n",
    " year={2024}, \n",
    "} \n",
    "```"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Congratulations! Time to join the Community!\n",
    "\n",
    "Congratulations on completing this tutorial notebook! If you enjoyed working through the tutorial, and want to continue working with DeepChem, we encourage you to finish the rest of the tutorials in this series. You can also help the DeepChem community in the following ways:\n",
    "\n",
    "## Star DeepChem on [GitHub](https://github.com/deepchem/deepchem)\n",
    "This helps build awareness of the DeepChem project and the tools for open source drug discovery that we're trying to build.\n",
    "\n",
    "\n",
    "## Join the DeepChem Discord\n",
    "The DeepChem [Discord](https://discord.gg/SxSzjRRDMA) hosts a number of scientists, developers, and enthusiasts interested in deep learning for the life sciences. Join the conversation!"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "deepchem",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.7"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
